package actor

import java.io.File
import java.nio.file.Files

import akka.actor.{Actor, ActorSystem, PoisonPill}
import akka.stream.Materializer
import command.{CommandExec, CommandExecutor, MissionUtils}
import dao._
import javax.inject.Inject
import models.Tables._
import org.apache.commons.io.FileUtils
import org.joda.time.DateTime
import play.api.libs.json.Json
import play.api.libs.ws.WSClient
import play.api.mvc.RequestHeader
import tool.Pojo._
import tool._

import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scala.util.{Failure, Success}
import implicits.Implicits._
import shared.VarTool
import utils.Utils
import scala.collection.parallel.CollectionConverters._

/**
 * Created by Administrator on 2019/10/24
 */
class MissionExecActor @Inject()(mission: MissionRow)(implicit val system: ActorSystem,
                                                      implicit val materializer: Materializer,
                                                      implicit val missionDao: MissionDao,
                                                      implicit val dao: MyDao
) extends Actor {

  val sampleDao = dao.sampleDao

  def splitBatchMission(workspaceDir: File, data: BatchMissionData) = {
    CommandExec().parExec { b =>
      Tool.batchFys(workspaceDir, data)
    }.map { b =>
     Tool.resultDeal(workspaceDir, mission, sampleDao)
    }
  }

  def noSplitBatchMission(workspaceDir: File) = {
    CommandExec().exec { b =>
      Tool.split(workspaceDir)
    }.exec { b =>
      //        Tool.noSplitBatchFys(workspaceDir)
      CommandData(workspaceDir, List[String]())
    }.map { b =>
      //      val fyDir = Tool.getFyWorkspaceDir(workspaceDir)
      //      val ids = fyDir.listFiles().map(_.getName)
      //      val threadNum = Tool.getMissionDefaultThreadNum
      //      ids.toList.par.threadNum(threadNum).foreach { id =>
      //        val sample = SampleRow(id, mission.userId, "", "", "", mission.missionName, new DateTime())
      //        val idDir = new File(fyDir, id)
      //        val f = sampleDao.insertOrUpdate(sample).map { x =>
      //          val sampleIdDir = SampleTool.getSampleIdDir(sample)
      //          Tool.getOutputXmlFile(idDir).fileCopyToDir(sampleIdDir)
      //          Tool.getStatFile(idDir).fileCopyToDir(sampleIdDir)
      //          Tool.produceReadsFile(sampleIdDir)
      //          Tool.produceSeqFile(sampleIdDir)
      //          Tool.produceSnpReadsFile(sampleIdDir)
      //          Tool.produceSnpSeqFile(sampleIdDir)
      //          Tool.produceBasicFile(sampleIdDir)
      //        }
      //        Utils.execFuture(f)
      //      }
    }

  }


  def batchMission(workspaceDir: File) = {
    val json = Utils.getJsonByConfigFile(workspaceDir)
    val data = FormTool.batchMissionForm.bind(json).get
    val isSplit = data.dataType == "hasSplit"
    if (isSplit) {
      splitBatchMission(workspaceDir, data)
    } else {
      noSplitBatchMission(workspaceDir)
    }
  }

  def compareMission(workspaceDir: File) = {
    CommandExec().map { b =>
      Tool.compareMission(workspaceDir)
    }
  }

  override def receive: Receive = {
    case "run" =>
      val newMision = mission.copy(state = "running")
      val userId = mission.userId
      val outDir = (mission.kind match {
        case VarTool.batchMissionStr => Tool.getUserMissionDir(mission.userId)
        case VarTool.compareMissionStr => Tool.getUserCompareMissionDir(mission.userId)
      })
      val missionDir = MissionUtils.getMissionDir(mission.id, outDir)
      val (workspaceDir, resultDir) = (missionDir.workspaceDir, missionDir.resultDir)
      val logFile = Tool.getLogFile(workspaceDir.getParentFile)
      missionDao.update(newMision).map { x =>
        val commandExec = mission.kind match {
          case VarTool.batchMissionStr => batchMission(workspaceDir)
          case VarTool.compareMissionStr => compareMission(workspaceDir)
        }
        val state = if (commandExec.isSuccess) {
          "success"
        } else {
          commandExec.errorInfo.toFile(logFile)
          "error"
        }
        val newMission = mission.copy(state = state, endTime = Some(new DateTime()))
        missionDao.update(newMission).map { x =>
        }
      }.onComplete {
        case Failure(exception) =>
          exception.printStackTrace()
          FileUtils.writeStringToFile(logFile, exception.getMessage)
          val newMission = mission.copy(state = "error", endTime = Some(new DateTime()))
          missionDao.update(newMission).map { x =>
          }
          self ! "stop"
        case Success(x) =>
          self ! "stop"
      }

    case "stop" =>
      self ! PoisonPill

  }
}
